<?php
/**
 * YBaseMailer.php
 *
 * @author Hua Yang <htmlcook@gmail.com>
 * @since 2.0
 */

Yii::import('common.components.mail.YMailerInterface');
Yii::import('common.components.mail.YMailEvent');

/**
 * Class YBaseMailer
 */
abstract class YBaseMailer extends CApplicationComponent implements YMailerInterface
{
	/**
	 * @var string
	 */
	public $htmlLayout = '//layouts/mail/html';

	/**
	 * @var string
	 */
	public $textLayout = '//layouts/mail/text';

	/**
	 * @var array
	 */
	public $messageConfig = array();

	/**
	 * @var string
	 */
	public $messageClass = 'common.components.email.YBaseMessage';

	/**
	 * @var bool
	 */
	public $useFileTransport = true;

	/**
	 * @var string
	 */
	public $fileTransportPath = 'common.runtime.mail';

	/**
	 * @var mixed
	 */
	public $fileTransportCallback;

	/**
	 * @param null $view
	 * @param array $params
	 * @return YMessageInterface
	 */
	public function compose($view = null, array $params = array())
	{
		$message = $this->createMessage();
		if ($view !== null) {
			$params['message'] = $message;
			if (is_array($view)) {
				if (isset($view['html'])) {
					$html = $this->render($view['html'], $params, $this->htmlLayout);
				}
				if (isset($view['text'])) {
					$text = $this->render($view['text'], $params, $this->textLayout);
				}
			} else {
				$html = $this->render($view, $params, $this->htmlLayout);
			}

			if (isset($html)) {
				$message->setHtmlBody($html);
			}
			if (isset($text)) {
				$message->setTextBody(strip_tags($text));
			}
		}
		return $message;
	}

	/**
	 * @return YMessageInterface
	 */
	protected function createMessage()
	{
		if (!isset($this->messageConfig['class'])) {
			$this->messageConfig['class'] = $this->messageClass;
		}

		return Yii::createComponent($this->messageConfig);
	}

	/**
	 * @param YMessageInterface $message
	 * @return bool
	 */
	public function send($message)
	{
		if (!$this->beforeSend($message)) {
			return false;
		}

		$address = $message->getTo();
		if (is_array($address)) {
			$address = implode(', ', array_keys($address));
		}

		Yii::log('Sending email "' . $message->getSubject() . '" to "' . $address . '"');

		if ($this->useFileTransport) {
			$isSuccessful = $this->saveMessage($message);
		} else {
			$isSuccessful = $this->sendMessage($message);
		}

		$this->afterSend($message, $isSuccessful);
		return $isSuccessful;
	}

	/**
	 * @param YMessageInterface $message
	 */
	abstract public function sendMessage($message);

	/**
	 * @param array $messages
	 * @return int
	 */
	public function sendMultiple(array $messages)
	{
		$successCount = 0;
		foreach ($messages as $message) {
			if ($this->send($message)) {
				$successCount++;
			}
		}
		return $successCount;
	}

	/**
	 * @param $view
	 * @param array $params
	 * @param bool $layout
	 * @return mixed|string
	 */
	public function render($view, $params = array(), $layout = false)
	{
		Yii::app()->getClientScript()->reset();
		$controller = new CController('mail');
		$controller->layout = $layout;
		return $controller->render($view, $params, true);
	}

	/**
	 * @return string
	 */
	public function generateMessageFileName()
	{
		$time = microtime(true);

		return date('Ymd-His-', $time) . sprintf('%04d', (int)(($time - (int)$time) * 10000)) . '-' . sprintf('%04d', mt_rand(0, 10000)) . '.eml';
	}

	/**
	 * @param YMessageInterface $message
	 * @return bool
	 */
	public function saveMessage($message)
	{
		$path = Yii::getPathOfAlias($this->fileTransportPath);
		if (!is_dir(($path))) {
			mkdir($path, 0777, true);
		}
		if ($this->fileTransportCallback !== null) {
			$file = $path . '/' . call_user_func($this->fileTransportCallback, $this, $message);
		} else {
			$file = $path . '/' . $this->generateMessageFileName();
		}
		file_put_contents($file, $message->toString());

		return true;
	}

	protected function beforeSend($message)
	{
		if ($this->hasEventHandler('onBeforeSend')) {
			$event = new YMailEvent($this);
			$event->message = $message;
			$this->onBeforeSend($event);
			return $event->isValid;
		} else {
			return true;
		}
	}

	/**
	 * @param YMailEvent $event
	 */
	protected function onBeforeSend($event)
	{
		$event->raiseEvent('onBeforeSend', $event);
	}

	protected function afterSend($message, $isSuccessful)
	{
		if ($this->hasEventHandler('afterSend')) {
			$event = new YMailEvent($this);
			$event->message = $message;
			$event->isSuccessful = $isSuccessful;
			$this->onAfterSend($event);
		}
	}

	/**
	 * @param YMailEvent $event
	 */
	protected function onAfterSend($event)
	{
		$event->raiseEvent('onAfterSend', $event);
	}
}